package com.threeti.jiayusms.domain.util;

import java.sql.Time;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.TimeZone;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.threeti.jiayusms.framework.util.StringUtil;


/**
 * Date Utils
 *
 * @author ben.z,runtao.yuan
 *
 */
public class DateUtil {

	private static final Logger log = Logger.getLogger(DateUtil.class);
	public static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
	public static final String DEFAULT_FORMAT_DATE = "yyyy-MM-dd";
	public static final String DEFAULT_FORMAT_DATE_TWO = "dd-MMM-yyyy";
	public static final String DEFAULT_FORMAT_DATE_EST = "MMMM, dd yyyy hh:mm:ss a";

	public static final SimpleDateFormat DEFAULT_TIME_FORMATTER_CN = new SimpleDateFormat("yyyy年MM月dd日HH时mm分");

  public static final SimpleDateFormat DEFAULT_TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/**
	 * convert date to string(yyyy-MM-dd HH:mm:ss)
	 *
	 * @return date string
	 */
	public static String toString(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_FORMAT);
		StringBuffer tb = new StringBuffer();
		if(date == null){
			return null;
		}
		return sdf.format(date, tb, new FieldPosition(0)).toString();

	}

	/**
	 * convert date to string for special format
	 *
	 * @param format
	 *
	 * @return date string
	 */
	public static String toString(Date date, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		StringBuffer tb = new StringBuffer();
		return sdf.format(date, tb, new FieldPosition(0)).toString();

	}

	public static String toString(Date date, String format, Locale locale) {
		SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ENGLISH);
		StringBuffer sb = new StringBuffer();
		return sdf.format(date, sb, new FieldPosition(0)).toString();
	}

	/**
	 * convert milliseconds to time string(hh:mm:ss)
	 *
	 * @param milliseconds
	 *
	 * @return time string
	 */
	public static String longToTimeString(long milliseconds) {
		long seconds = milliseconds / 1000;
		int hours = (int) (seconds / (60 * 60));
		seconds = seconds % (60 * 60);
		int minutes = (int) (seconds / 60);
		seconds = (int) (seconds % 60);

		String hoursStr = hours < 10 ? ("0" + hours) : ("" + hours);
		String minutesStr = minutes < 10 ? ("0" + minutes) : "" + minutes;
		String secondsStr = seconds < 10 ? ("0" + seconds) : "" + seconds;
		return hoursStr + ":" + minutesStr + ":" + secondsStr;
	}

	public static String longToTimeString(long milliseconds, boolean hasSecond) {
		long seconds = milliseconds / 1000;
		int hours = (int) (seconds / (60 * 60));
		seconds = seconds % (60 * 60);
		int minutes = (int) (seconds / 60);
		seconds = (int) (seconds % 60);

		String hoursStr = hours < 10 ? ("0" + hours) : ("" + hours);
		String minutesStr = minutes < 10 ? ("0" + minutes) : "" + minutes;
		String secondsStr = seconds < 10 ? ("0" + seconds) : "" + seconds;
		if (hasSecond) {
			return hoursStr + ":" + minutesStr + ":" + secondsStr;
		} else {
			return hoursStr + ":" + minutesStr;
		}
	}

	/**
	 * convert milliseconds to time array(hh,mm,ss)
	 *
	 * @param milliseconds
	 *
	 * @return time array
	 */
	public static int[] longToTimeArray(long milliseconds) {
		long seconds = milliseconds / 1000;
		int hours = (int) (seconds / (60 * 60));
		seconds = seconds % (60 * 60);
		int minutes = (int) (seconds / 60);
		seconds = (int) (seconds % 60);

		int[] returnArray = new int[3];
		returnArray[0] = (int) hours;
		returnArray[1] = (int) minutes;
		returnArray[2] = (int) seconds;
		return returnArray;
	}

	/**
	 * convert time string to milliseconds
	 *
	 * @param time
	 *            string
	 *
	 * @return milliseconds
	 */
	public static long timeStringToLong(String timeFormat) throws Exception {
		StringTokenizer token = new StringTokenizer(timeFormat, ":");
		if (token.countTokens() != 3) {
			throw new Exception("invalidate format");
		}
		int[] values = new int[3];
		long returnVal = 0;
		int i = 0;
		while (token.hasMoreTokens()) {
			int val = Integer.parseInt(token.nextToken());
			values[i] = val;
			i++;
		}
		returnVal = values[0] * 60 * 60 * 1000 + values[1] * 60 * 1000
				+ values[2] * 1000;
		return returnVal;
	}

	/**
	 * convert date to date string
	 *
	 * @param date
	 * @param hasTime
	 *
	 * @return date string
	 */
	public static String toString(Date date, boolean hasTime) {
		SimpleDateFormat sdf;
		if (hasTime) {
			sdf = new SimpleDateFormat(DEFAULT_FORMAT);
		} else {
			sdf = new SimpleDateFormat(DEFAULT_FORMAT_DATE);
		}
		StringBuffer tb = new StringBuffer();
		return sdf.format(date, tb, new FieldPosition(0)).toString();

	}

	/**
	 * convert current date to date string
	 *
	 * @param format
	 *
	 * @return date string
	 */
	public static String toString(String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		StringBuffer tb = new StringBuffer();
		return sdf.format(new Date(), tb, new FieldPosition(0)).toString();

	}

	/**
	 * convert date string to date array(year,month,date of month)
	 *
	 * @param date
	 *            string (yyyMMdd)
	 *
	 * @return date array(year,month,date of month)
	 */
	public static int[] getDateArray(String outputDate) {
		int[] outDate = new int[3];
		if (outputDate == null)
			return null;
		if (outputDate.trim().length() >= 8) {
			outDate[0] = Integer.parseInt(outputDate.substring(0, 4));
			outDate[1] = Integer.parseInt(outputDate.substring(4, 6));
			outDate[2] = Integer.parseInt(outputDate.substring(6, 8));
		}
		return outDate;
	}

	/**
	 * get number of date from date string(yyyy-mm-dd\yyyy-mm-dd HH:mm:ss)
	 *
	 * @param date
	 *            string
	 *
	 * @return number of date(eg:"20021210" or "20021210122403")
	 */
	public static String getDateNumberString(String dateString) {
		String outDate = "";
		String y;
		String m;
		String d;
		String h;
		String mi;
		String s;
		if (dateString == null)
			return outDate;
		if (dateString.length() == 10 || dateString.length() == 19) {
			y = dateString.substring(0, 4);
			m = dateString.substring(5, 7);
			d = dateString.substring(8, 10);
			outDate = y + m + d;
			if (dateString.length() > 10) {
				h = dateString.substring(11, 13);
				mi = dateString.substring(14, 16);
				s = dateString.substring(17, 19);
				outDate += h + mi + s;
			}
		}
		return outDate;
	}

	/**
	 *
	 * This method use to convert specified date string and timeZone to local
	 * TimeZone date.
	 *
	 * Example: If you set str="2008-11-28 15:00:00" and
	 * format="yyyy-MM-dd HH:mm:ss" and timeZone="GMT+11:00" this method will
	 * return a Date represent "2008-11-28 12:00:00"
	 *
	 * @param str
	 *            date string like this "2008-11-28 20:00:00"
	 * @param format
	 *            date format like this "yyyy-MM-dd HH:mm:ss"
	 * @param locale
	 *            local language
	 * @param timeZone
	 *            timeZone pattern like this "GMT+11:00"
	 * @return {@link Date} Local host date
	 */
	public static Date stringToDateWithTimeZone(String str, String format,
			Locale locale, TimeZone timeZone) {
		SimpleDateFormat sdf = new SimpleDateFormat(format, locale);


//		log.info("local TimeZone ID : " + TimeZone.getDefault().getID());
//		sdf.setTimeZone(TimeZone.getDefault());

//		if (StringUtil..isTimeZone(timeZone))
//			sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
			sdf.setTimeZone(timeZone);
//		else
//			log.warn("Invalid TimeZone pattern! [" + timeZone + "]");

		try {

			return sdf.parse(str);
		} catch (ParseException e) {
			log.error(e, e);
			return null;
		}
	}

	/**
	 * convert date string to date
	 *
	 * @param date
	 * @param format
	 * @return date
	 */
	public static Date stringToDate(String str, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		try {
			return sdf.parse(str);
		} catch (Exception e) {
			return null;
		}
	}

	public static Date stringToDate(String str, String format, Locale locale) {
		SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
		try {
			return sdf.parse(str);
		} catch (ParseException e) {
			return null;
		}
	}

	public static String stringToString(String str, String fromFormat,
			String toFormat, Locale locale) {
		Date date = stringToDate(str, fromFormat, locale);
		return toString(date, toFormat, locale);
	}

	/**
	 * convert time string to millisecond
	 *
	 * @param time
	 * @return millisecond
	 */
	public static long stringToMillisecond(String str) {
		long ret = 0;

		String[] t = str.split("\\:");
		long s = 1;
		for (int i = t.length - 1; i >= 0; i--) {
			if (StringUtil.isNumber(t[i])) {
				ret += Long.parseLong(t[i]) * s;
			}
			s *= 60;
		}

		ret *= 1000;

		return ret;
	}

	/**
	 * convert millisecond to string
	 *
	 * @param millisecond
	 * @return time
	 */
	public static String millisecondToString(long ms) {
		ms /= 1000;
		long hh = ms / (60 * 60);
		long mm = (ms % (60 * 60)) / 60;
		long ss = (ms % (60 * 60)) % 60;

		return String.valueOf(hh) + ":" + String.valueOf(mm) + ":"
				+ String.valueOf(ss);
	}

	/**
	 * trim time from date
	 *
	 * @param date
	 * @return
	 */
	public static Date trimDateTime(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * get date time
	 *
	 * @param aMask
	 * @param aDate
	 * @return
	 */
	public static final String getDateTime(Date aDate, String aMask) {
		SimpleDateFormat df = null;
		String returnValue = "";

		if (aDate == null) {
			return null;
		} else {
			df = new SimpleDateFormat(aMask);
			returnValue = df.format(aDate);
		}
		return (returnValue);
	}

	/*
 *
 */
	public static Date addDate(Date date, int field, int mount) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(field, mount);
		return calendar.getTime();
	}

	public static Date addDate(Date date, int field, int mount, Locale locale) {
		Calendar calendar = Calendar.getInstance(locale);
		calendar.setTime(date);
		calendar.add(field, mount);
		return calendar.getTime();
	}

	public static Date addDay(Date date, int i) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_YEAR, i);
		return calendar.getTime();
	}

	public static String addOneDay(String dateStr, String format) {
		Date date = stringToDate(dateStr, format, Locale.ENGLISH);
		return toString(addDate(date, Calendar.DAY_OF_MONTH, 1), format,
				Locale.ENGLISH);
	}

	public static Date getDate(Date date) {
		Date time = DateUtil.stringToDate(DateUtil.toString(date,
				DEFAULT_FORMAT_DATE)
				+ " 23:59:59", DEFAULT_FORMAT);

		return time;
	}

	public static Date getZeroDate(Date date){
		Date time = DateUtil.stringToDate(DateUtil.toString(date,
				DEFAULT_FORMAT_DATE)
				+ " 00:00:00", DEFAULT_FORMAT);

		return time;
	}

	public static Date stringToDate(String str) {
		SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_FORMAT);
		try {
			return sdf.parse(str);
		} catch (ParseException e) {
			return null;
		}
	}

	public static Date stringToSqlDate(String str) {
		SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_FORMAT_DATE);
		try {
			return new java.sql.Date(sdf.parse(str).getTime());
		} catch (ParseException e) {
			return null;
		}
	}

	public static Date generateDate() {
		Calendar cld = new GregorianCalendar();
		Date date = new Date(cld.getTimeInMillis());
		return date;
	}

	public static String getTimeStamp() {
		Long timeStamp = System.currentTimeMillis();
		Double random = Math.random();
		String randomtx = random.toString();
		if (randomtx.length() > 7) {
			randomtx = randomtx.substring(2, 5);
		} else {
			randomtx = randomtx.substring(2);
		}

		String timestamp = timeStamp.toString() + randomtx;
		return timestamp;
	}

	public static Date timeZone2Local(Date date, boolean hasTimeZoneID) {
		return stringToDate(timeZone2Local(date, "UTC"));
	}

	public static String timeZone2Local(Date date, String timeZoneID) {
		SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_FORMAT);
		int diffTime = getDiffTimeZoneRawOffset(timeZoneID);
		Date d = new Date(date.getTime() + diffTime);
		return sdf.format(d);
	}

	public static int getDiffTimeZoneRawOffset(String timeZoneId) {
		return TimeZone.getDefault().getRawOffset()
				- TimeZone.getTimeZone(timeZoneId).getRawOffset();
	}

	public static int getOffset2GMT(String timeZoneId){
		if(timeZoneId == null){
			return -1;
		}
		return TimeZone.getTimeZone(timeZoneId).getRawOffset() - TimeZone.getTimeZone("UTC").getRawOffset();
	}

	public static Boolean judgeDiffTime(Date oldTime,Date currentTime,long diffTime){
		Boolean flag = false;
		if(oldTime == null){
			return flag;
		}
		long oTime = oldTime.getTime();
		long cTime = currentTime.getTime();
		long dTime = cTime - oTime;
		if(dTime >= diffTime){
			flag = true;
		}
		return flag;

	}

	public static String currentTimeToEST(Date currentTime){
		Format estFormat = new SimpleDateFormat(DEFAULT_FORMAT_DATE_EST);
		String estTime = estFormat.format(currentTime);
		estTime = estTime +" EST";
		return estTime;
	}


	public static Date transformTimeZone(String date,String timaZone){
		Date d = new Date();
		TimeZone tz = TimeZone.getTimeZone(timaZone);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		sdf.setTimeZone(TimeZone.getTimeZone(tz.getID()));
		try {
			d = sdf.parse(DateUtil.toString(DateUtil.stringToDate(date)));
		} catch (ParseException e) {
			log.info("event start time : " + date + ", TimeZone : " + timaZone);
			return null;
		}
		return d;
	}

	public static String querySendTime(String strDate ,String[] str){
		String returnMessage;

		Calendar setUpDate = Calendar.getInstance();
		setUpDate.setTime(DateUtil.stringToDate(strDate,DEFAULT_FORMAT_DATE));

		Calendar nowDate = Calendar.getInstance();
		nowDate.setTime(DateUtil.stringToDate(DateUtil.toString(new Date()),DEFAULT_FORMAT_DATE));

		if(setUpDate.getTimeInMillis() == nowDate.getTimeInMillis()){
			boolean b = false;
			int i = 0;
			for (;i < str.length; i++) {
				if( Calendar.getInstance().get(Calendar.HOUR_OF_DAY) < Integer.parseInt(str[i]) ){
					b = true;
					break;
				}
			}
			if(b){
				setUpDate.set(Calendar.HOUR_OF_DAY,  Integer.parseInt(str[i]));
			}else{
				setUpDate.add(Calendar.DATE, 1);
				setUpDate.set(Calendar.HOUR_OF_DAY, Integer.parseInt(str[0]));
			}
			returnMessage = DateUtil.toString(setUpDate.getTime());
		}else if(setUpDate.getTimeInMillis() > nowDate.getTimeInMillis()){
			setUpDate.set(Calendar.HOUR_OF_DAY, Integer.parseInt(str[0]));
			returnMessage = DateUtil.toString(setUpDate.getTime());
		}else{
			returnMessage = "invalid";
		}
		return returnMessage;
	}

  public static String[] querySendTime2(String timeSegement) {
    String[] segements = timeSegement.split(",");
    Calendar timeHandler = Calendar.getInstance();
    int currentHour = timeHandler.get(Calendar.HOUR_OF_DAY);
    
    //快速预扫描，查找是否有符合立即发送的时间段
    boolean fired = false;
    boolean isNextFireHourTodayMatched = false;
    int nextFireHourToday = -1;
    for (String hourlyTime : segements) {
      if (StringUtils.isNumeric(hourlyTime)) {//时点
        if (currentHour == Integer.parseInt(hourlyTime)) {
          fired = true;
          return new String[]{"0", DEFAULT_TIME_FORMATTER.format(new Date())};//立即发送，返回进一步的实时时间 TODO 可能要预留出延迟时间
        }
        if (!isNextFireHourTodayMatched) {//match once
          if (currentHour < Integer.parseInt(hourlyTime)) {
            nextFireHourToday = Integer.parseInt(hourlyTime);
            isNextFireHourTodayMatched = true;
          }          
        }
      } else {//时段
        String[] segement = hourlyTime.split("~");
        int startIndex = Integer.parseInt(segement[0]);
        int endIndex = Integer.parseInt(segement[1]);
        for (int hour = startIndex; hour <= endIndex; hour++) {
          if (currentHour == hour) {
            fired = true;
            return new String[]{"0", DEFAULT_TIME_FORMATTER.format(new Date())};//立即发送，返回进一步的实时时间 TODO 可能要预留出延迟时间
          }          
          if (!isNextFireHourTodayMatched) {//match once
            if (currentHour < hour) {
              nextFireHourToday = hour;
              isNextFireHourTodayMatched = true;
            }          
          }          
        }
      }
    }
    
    if (!fired) {
      //TODO 不推进至明日的实现
      if (isNextFireHourTodayMatched && nextFireHourToday != -1) {
        timeHandler.set(Calendar.HOUR_OF_DAY, nextFireHourToday);
        timeHandler.set(Calendar.MINUTE, 0);
        timeHandler.set(Calendar.SECOND, 0);
        return new String[]{"1", DEFAULT_TIME_FORMATTER.format(timeHandler.getTime())};
      }
      
      String nextFireHour = segements[0];
      timeHandler.add(Calendar.DAY_OF_MONTH, 1);//推进1天
      timeHandler.set(Calendar.MINUTE, 0);
      timeHandler.set(Calendar.SECOND, 0);
      if (StringUtils.isNumeric(nextFireHour)) {//时点
        timeHandler.set(Calendar.HOUR_OF_DAY, Integer.parseInt(nextFireHour));
        return new String[]{"1", DEFAULT_TIME_FORMATTER.format(timeHandler.getTime())};
      }
      nextFireHour = nextFireHour.split("~")[0];
      timeHandler.set(Calendar.HOUR_OF_DAY, Integer.parseInt(nextFireHour));
      return new String[]{"1", DEFAULT_TIME_FORMATTER.format(timeHandler.getTime())};
      
      //return querySendTime2(availableDate, nowUnSafe, timeSegement);
    }
    
    
    return null;
  }


	public static void main(String[] args) {
//		String [] str = {"1","11","20","21", "22"};
//		String strDate = "2010-09-28";
//
//		System.out.println(querySendTime(strDate, str));
		
		String input = "10~18";
    String[] rtn = querySendTime2(input);
    
    if (rtn != null) {
      System.out.println(rtn[0]);
      System.out.println(rtn[1]);
    }
	}

}